package com.tbit.uqbike.client.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import com.tbit.common.constant.BusinessConstant;
import com.tbit.common.constant.PayPlatformContent;
import com.tbit.common.constant.RideLogDetailsConstant;
import com.tbit.uqbike.client.constant.AccountConfigExtConstant;
import com.tbit.uqbike.client.constant.AdAccountFeeConstant;
import com.tbit.uqbike.client.constant.CardTypeConstant;
import com.tbit.uqbike.client.dao.capital.CardUseLogDao;
import com.tbit.uqbike.client.dao.capital.RideLogDetailsDao;
import com.tbit.uqbike.client.dao.core.*;
import com.tbit.uqbike.client.exception.BaseException;
import com.tbit.uqbike.client.pojo.*;
import com.tbit.uqbike.client.pojo.dto.UnpaidOrderUseCarDTO;
import com.tbit.uqbike.client.pojo.newEntity.AccountConfigExt;
import com.tbit.uqbike.client.pojo.vo.UnpaidOrderCanUseCarVO;
import com.tbit.uqbike.client.pojo.vo.UnpaidOrderUseCarFee;
import com.tbit.uqbike.client.pojo.vo.UnpaidOrderUseRideCar;
import com.tbit.uqbike.client.service.*;
import com.tbit.uqbike.client.util.DateTimeUtil;
import com.tbit.uqbike.client.util.MoneyUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

import static com.tbit.uqbike.client.constant.AccountConfigExtConstant.*;
import static com.tbit.uqbike.client.constant.MemberCardConstant.*;

/**
 * 未支付订单卡券抵扣相关功能接口实现
 *
 * @author <a href="mailto:chen.wutian@tbit.com.cn">BUGTian</a>
 * @since 2025/5/15
 */
@Service
@Slf4j
public class UnpaidOrderDeductionServiceImpl implements UnpaidOrderDeductionService {

    @Autowired
    private RideLogService rideLogService;

    @Resource
    private RideCardUserDao rideCardUserDao;

    @Resource
    private VipCardLogDao vipCardLogDao;

    @Resource
    private CacheService cacheService;

    @Resource
    private CouponUserDao couponUserDao;

    @Resource
    private AdAccountFeeService adAccountFeeService;

    @Autowired
    private RideCardUserService rideCardUserService;

    @Autowired
    private RideCardService rideCardService;

    @Resource
    private RideLogDetailsDao rideLogDetailsDao;

    @Resource
    private VipCardDao vipCardDao;

    @Autowired
    private UserService userService;

    @Resource
    private RideCardDao rideCardDao;

    @Resource
    private CouponDao couponDao;

    @Autowired
    private UserAccountMoneyService userAccountMoneyService;

    @Autowired
    private CardUseLogDao cardUseLogDao;


    @Autowired
    private RideLogDao rideLogDao;

    @Autowired
    CouponUserService couponUserService;


    @Override
    public UnpaidOrderCanUseCarVO getUnpaidOrderCanUseCar(String orderNO) {
        RideLog rideLog = rideLogService.getByOrderNO(orderNO);
        if (rideLog == null || rideLog.getPayTime() != null) {
            //订单不存在或者已支付直接返回空
            return null;
        }
        RideLogDetails rideLogDetails = rideLogDetailsDao.getByOrderId(rideLog.getOrderNO());
        if (rideLogDetails == null || (rideLogDetails.getCardDeductionMoney() != null && rideLogDetails.getCardDeductionMoney() > 0)) {
            //如果有卡券抵扣过的，不允许重复使用卡券
            return null;
        }

        Integer accountId = rideLog.getAccountId();
        Integer userId = rideLog.getUserId();
        UnpaidOrderCanUseCarVO unpaidOrderCanUseCarVO = new UnpaidOrderCanUseCarVO();
        List<AccountConfigExt> accountConfigExtList = cacheService.getAccountConfigExtByKeys(accountId, ListUtil.of(UNPAID_ORDER_DEDUCTION_CONFIG_RIDE_CARD, UNPAID_ORDER_DEDUCTION_CONFIG_VIP_CARD, UNPAID_ORDER_DEDUCTION_CONFIG_COUPON));
        for (AccountConfigExt accountConfigExt : accountConfigExtList) {
            if (accountConfigExt.getParamValue() == null || Objects.equals(accountConfigExt.getParamValue(), "0")) {
                continue;
            }
            //配置了才去查，避免重复查库
            switch (accountConfigExt.getParamKey()) {
                case UNPAID_ORDER_DEDUCTION_CONFIG_RIDE_CARD:
                    AdAccountFee fee = adAccountFeeService.getFee(accountId, rideLog.getMachineId(), rideLog.getStartTime());
                    //判断是否能使用
                    List<RideCardUser> rideCardUsers = rideCardUserService.getRideVaildCard(userService.getByUserId(userId), accountId, fee.getFeeId());
                    //校验骑行卡是否在有效日期和有效周几
                    rideCardUsers = rideCardService.checkValidaDate(rideCardUsers, rideLog.getStartTime());
                    RideCardUser rideCardUser = Optional.ofNullable(rideCardUsers).filter(o -> !o.isEmpty()).map(o -> o.get(0)).orElse(null);
                    if (rideCardUser != null) {
                        RideCard rideCard = rideCardDao.getById(rideCardUser.getRideCardId());
                        if (rideCard != null) {
                            unpaidOrderCanUseCarVO.setUnpaidOrderUseRideCar(
                                    new UnpaidOrderUseRideCar()
                                            .setRideCardId(rideCard.getRideCardId())
                                            .setName(rideCard.getName())
                                            .setRidecardType(rideCard.getRidecardType())
                                            .setUserType(rideCard.getUserType())
                                            .setTimeCount(rideCard.getTimeCount())
                                            .setStartDate(rideCardUser.getStartDate())
                                            .setEndDate(rideCardUser.getEndDate())
                                            .setCurrentNum(rideCardUser.getCurrentNum())
                                            .setUseCount(rideCardUser.getUseCount()));
                        }
                    }
                    break;
                case UNPAID_ORDER_DEDUCTION_CONFIG_VIP_CARD:
                    unpaidOrderCanUseCarVO.setVipCard(vipCardLogDao.getVipCardByUserId(accountId, userId));
                    break;
                case UNPAID_ORDER_DEDUCTION_CONFIG_COUPON:
                    unpaidOrderCanUseCarVO.setCouponUserList(couponUserDao.getMoneyCoupon(MapUtil.builder(new HashMap<String, Object>())
                            .put("accountId", accountId)
                            .put("userId", userId).build()));
                    break;
                default:
                    break;
            }
        }
        return unpaidOrderCanUseCarVO;
    }

    @Override
    public UnpaidOrderUseCarFee getFee(String orderNO, UnpaidOrderUseCarDTO unpaidOrderUseCarDTO) {
        RideLog rideLog = rideLogService.getByOrderNO(orderNO);
        if (rideLog == null || rideLog.getPayTime() != null) {
            throw new BaseException("订单不存在 或 订单已支付");
        }
        //默认值，防止返回空导致前端报错
        RideLogDetails rideLogDetails = rideLogDetailsDao.getByOrderId(orderNO);
        if (rideLogDetails == null) {
            throw new BaseException("订单异常，请联系客服处理");
        }
        UnpaidOrderUseCarFee unpaidOrderUseCarFee = new UnpaidOrderUseCarFee(0L, rideLog.getMoney().longValue() , rideLogDetails);
        //骑行时长（秒）
        Long rideTime = DateUtil.between(DateUtil.parse(rideLog.getStartTime()), DateUtil.parse(rideLog.getEndTime()), DateUnit.SECOND);
        //骑行费用（分）
        long money = rideLogDetails.getDeductionCyclingMoney();
        //获取计费规则
        AdAccountFee fee = adAccountFeeService.getFee(rideLog.getAccountId(), rideLog.getMachineId(), rideLog.getStartTime());
        if (!Objects.isNull(unpaidOrderUseCarDTO.getRideCardId())) {
            RideCardUser rideCardUser = rideCardUserDao.getRideCardId(unpaidOrderUseCarDTO.getRideCardId(), rideLog.getUserId());
            if (rideCardUser == null) {
                return unpaidOrderUseCarFee;
            }
            unpaidOrderUseCarFee.setDeductionCardType(CardTypeConstant.TYPE_RIDECARD);
            unpaidOrderUseCarFee.setRideCardUser(rideCardUser);
            Long rideCardCanDeductionMoney = getRideCardCanDeductionMoney(fee, rideCardUser.getRidecardType(), rideCardUser.getTimeCount() == null ? 0 : rideCardUser.getTimeCount(), money, rideTime, rideLog.getMileage(), rideLog.getAccountId());
            unpaidOrderUseCarFee.setCanDeductionMoney(rideCardCanDeductionMoney).computeDeductionEndMoney(money);
            unpaidOrderUseCarFee.setCardNO(rideCardUser.getOrderNO());
        }
        if (!Objects.isNull(unpaidOrderUseCarDTO.getVipId())) {
            VipCard vipCard = vipCardDao.getById(unpaidOrderUseCarDTO.getVipId());
            if (vipCard == null) {
                return unpaidOrderUseCarFee;
            }
            unpaidOrderUseCarFee.setDeductionCardType(CardTypeConstant.TYPE_VIP);
            unpaidOrderUseCarFee.setVipCard(vipCard);
            double discount = vipCard.getDiscount();
            long vipCardCanDeductionMoney;
            switch (vipCard.getType()) {
                //折扣卡
                case VIP_CARD_DISCOUNT:
                    //折扣率
                    double discountRate = discount / 10;
                    vipCardCanDeductionMoney = money - (long)MoneyUtil.formatDouble(money * discountRate);
                    //防止折扣设置有误，从而返回负数
                    vipCardCanDeductionMoney = (money - vipCardCanDeductionMoney) <= 0 ? money : (money - vipCardCanDeductionMoney);
                    return unpaidOrderUseCarFee.setCanDeductionMoney(vipCardCanDeductionMoney).computeDeductionEndMoney(money);
                //减免费用
                case VIP_CARD_REDUCE:
                    //减免费用（分）
                    long discountMoney = (long)NumberUtil.mul(discount, 100D);
                    vipCardCanDeductionMoney = (money - discountMoney) <= 0 ? money : (money - discountMoney);
                    return unpaidOrderUseCarFee.setCanDeductionMoney(vipCardCanDeductionMoney).computeDeductionEndMoney(money);
                //自定义会员卡计费
                case VIP_CARD_VIPFEE:
                    AdAccountFee vipFee = adAccountFeeService.getVipFee(rideLog.getAccountId(), rideLog.getStartTime(), vipCard.getVipId());
                    if (vipFee == null) {
                        return unpaidOrderUseCarFee;
                    }
                    //判断是否满足会员免费骑行
                    int freeType = MoneyUtil.countFreeType(DateTimeUtil.getMinuteByTime(rideLog.getStartTime(), rideLog.getEndTime(), 1, 0),
                            rideLogDetails.getMileage(), vipFee.getFreeTime(), vipFee.getFreeDistance(), vipFee.getFreeConditionType());
                    //默认满足免费骑行
                    long vipFeeCanDeductionMoney = money;
                    //不满足免费骑行
                    if (AdAccountFeeConstant.FREE_RIDE_TYPE_NOT_FREE == freeType) {
                        Double newMoney = MoneyUtil.getRide(rideLog.getMileage(), rideTime.intValue(), vipFee, false);
                        vipFeeCanDeductionMoney = (money - newMoney.longValue()) <= 0 ? 0 : (money - newMoney.longValue());
                    }
                    return unpaidOrderUseCarFee.setCanDeductionMoney(vipFeeCanDeductionMoney).computeDeductionEndMoney(money);
                default:
                    return unpaidOrderUseCarFee;
            }
        }
        if (!Objects.isNull(unpaidOrderUseCarDTO.getCouponuserId())) {
            Coupon coupon = couponDao.getByCouponUserId(unpaidOrderUseCarDTO.getCouponuserId());
            if (coupon == null) {
                return unpaidOrderUseCarFee;
            }
            unpaidOrderUseCarFee.setDeductionCardType(CardTypeConstant.TYPE_MEAL);
            unpaidOrderUseCarFee.setCoupon(coupon);
            long couponCanDeductionMoney = 0;
            //金额减免
            if (GiftCard.moneyCoupon.equals(coupon.getCouponType())) {
                Integer couponMoney = coupon.getCouponMoney();
                couponCanDeductionMoney = (money - couponMoney) <= 0 ? money : couponMoney;
            }
            //时长减免
            if (GiftCard.timeCoupon.equals(coupon.getCouponType())) {
                Integer couponTime = coupon.getCouponTime();
                if (rideTime <= couponTime) {
                    //抵扣全部骑行金额
                    couponCanDeductionMoney = money;
                } else {
                    rideTime = rideTime - couponTime;
                    long newRideMoney = MoneyUtil.getRide(rideLog.getMileage(), rideTime.intValue(), fee, false).longValue();
                    //新的骑行金额不能比旧的骑行金额高(避免计费调整的情况)
                    couponCanDeductionMoney = (money - newRideMoney) <= 0 ? 0 : (money - newRideMoney);
                }
            }
            return unpaidOrderUseCarFee.setCanDeductionMoney(couponCanDeductionMoney).computeDeductionEndMoney(money);
        }
        //防止未传卡券的情况下，返回原有金额，抵扣0元
        return unpaidOrderUseCarFee;
    }

    @Override
    public Boolean useCar(String orderNO, UnpaidOrderUseCarDTO unpaidOrderUseCarDTO, User user) {
        UnpaidOrderUseCarFee unpaidOrderUseCarFee = getFee(orderNO, unpaidOrderUseCarDTO);
        Integer deductionCardType = unpaidOrderUseCarFee.getDeductionCardType();
        RideLogDetails rideLogDetails = unpaidOrderUseCarFee.getRideLogDetails();
        //当前使用卡券可抵扣金额
        Long canDeductionMoney = unpaidOrderUseCarFee.getCanDeductionMoney();
        //使用卡券抵扣后骑行金额 = 抵扣后骑行金额 - 当前使用卡券可抵扣金额
        Long deductionCyclingMoney = rideLogDetails.getDeductionCyclingMoney() - canDeductionMoney;
        Long deductionAfterMoney = rideLogDetails.getDeductionEndMoney();
        //使用卡券抵扣后总金额 = 抵扣后总金额 - 当前使用卡券可抵扣金额
        Long deductionEndMoney = deductionAfterMoney - canDeductionMoney;
        if (canDeductionMoney > 0) {
            Date now = new Date();
            //1、使用卡券
            CardUseLog cardUseLog = new CardUseLog()
                    .setAccountId(user.getAccountId())
                    .setUseAccountId(rideLogDetails.getAccountId())
                    .setAddTime(now)
                    .setUserId(user.getUserId())
                    .setMoney(canDeductionMoney.intValue())
                    .setOrderNO(rideLogDetails.getOrderId());;
            switch (deductionCardType) {
                case CardTypeConstant.TYPE_RIDECARD:
                    //用户使用骑行卡抵扣
                    RideCardUser rideCardUser = unpaidOrderUseCarFee.getRideCardUser();
                    cardUseLog.setBuyAccountId(rideCardUser.getAccountId())
                            .setCardId(rideCardUser.getRideCardId())
                            .setCardType(CardTypeConstant.TYPE_RIDECARD)
                            .setCardName(rideCardUser.getName());
                    rideCardUserService.updateUseCount(unpaidOrderUseCarFee.getCardNO());
                    break;
                case CardTypeConstant.TYPE_VIP:
                    //用户使用会员卡抵扣
                    VipCard vipCard = unpaidOrderUseCarFee.getVipCard();
                    cardUseLog.setBuyAccountId(vipCard.getAccountId())
                            .setCardId(vipCard.getVipId())
                            .setCardType(CardTypeConstant.TYPE_VIP)
                            .setCardName(vipCard.getName());
                    break;
                case CardTypeConstant.TYPE_MEAL:
                    //用户使用优惠券抵扣
                    Coupon coupon = unpaidOrderUseCarFee.getCoupon();
                    cardUseLog.setBuyAccountId(coupon.getAccountId())
                            .setCardId(coupon.getCouponId())
                            .setCardType(CardTypeConstant.TYPE_MEAL)
                            .setCardName(coupon.getName());
                    couponUserService.edit(unpaidOrderUseCarDTO.getCouponuserId());
                    break;
                default:
                    throw new BaseException("当前卡券类型暂不支持使用");
            }
            cardUseLogDao.add(cardUseLog);
            //2、修改订单金额
            rideLogDetails.setDeductionCyclingMoney(deductionCyclingMoney);
            rideLogDetails.setDeductionEndMoney(deductionEndMoney);
            rideLogDetails.setCardDeductionMoney(canDeductionMoney);
            unpaidOrderUseCarDTO.setBillingDetails(canDeductionMoney, rideLogDetails, now, unpaidOrderUseCarFee.getDeductionCardType());
            //2.1、修改骑行订单的卡券抵扣
            RideLog rideLog = new RideLog();
            rideLog.setOrderNO(orderNO);
            rideLog.setMoney(deductionEndMoney.doubleValue());
            rideLog.setRemark(rideLogDetails.getBillingDetails());
            rideLog.setPayTime(DateUtil.formatDateTime(rideLogDetails.getPayTime()));
            //2.2、修改用户表欠款金额和用户区域欠款
            Integer userId = rideLogDetails.getUserId();
            //没有抵扣全部骑行订单金额的情况下才需要判断
            if (!RideLogDetailsConstant.ORDER_PAY.equals(rideLogDetails.getPayStatus())) {
                //3、判断余额是否够支付
                User userDB = userService.getByUserId(userId);
                int userMoney = userDB.getMoney().intValue();
                if (userMoney >= rideLogDetails.getDeductionEndMoney()) {
                    rideLog.setPayTime(DateUtil.formatDateTime(now));
                    rideLogDetails.setPayStatus(RideLogDetailsConstant.ORDER_PAY);
                    rideLogDetails.setPayTime(now);
                    Long newUserMoney = userMoney - rideLogDetails.getDeductionEndMoney();
                    userService.updateUserMoney(userDB.getUserId(), newUserMoney, now);
                    //插入新表和旧表的流水记录
                    String remark = String.format("余额扣费%s元", toYuan(deductionEndMoney));
                    rideLogDetails.setBillingDetails(rideLogDetails.getBillingDetails() + "," + remark);
                    rideLog.setRemark(rideLogDetails.getBillingDetails());
                    userAccountMoneyService.editMoney(user, orderNO, rideLogDetails.getDeductionEndMoney(), PayPlatformContent.PAY_BALANCE, rideLogDetails.getAccountId(), PayPlatformContent.PAY_USE, now.getTime(), remark, BusinessConstant.BUSINESS_BALANCE_OF_CYCLING);
                    //抵扣后欠款为0元
                    deductionEndMoney = 0L;
                }
            }
            rideLogDao.updateByOrderNOSelective(rideLog);
            rideLogDetailsDao.updateCardDeduction(rideLogDetails);
            userService.updateRideMoney(new User().setRideMoney(deductionEndMoney).setUserId(userId).setUpdateTime(DateUtil.formatDateTime(now)));
            userAccountMoneyService.updateRideMoney(deductionAfterMoney, deductionEndMoney, userId, rideLogDetails.getAccountId(), now.getTime(), user, rideLogDetails);
        }

        return true;
    }

    /**
     * 分转元
     * @param money 金额（分）
     * @return 元
     */
    private String toYuan(Long money) {
        return String.format("%.2f", ((double) money / 100D));
    }


    /**
     * 获取骑行卡抵扣费用
     *
     * @param adAccountFee 计费规则
     * @param ridecardType 骑行卡类型 0：时长减免，1：费用减免
     * @param timeCount    时长/金额，骑行卡类型是时长减免时=时长（单位：分），骑行卡类型是费用时=金额（单位：分）
     * @param money        骑行金额
     * @param rideTime     骑行时长（秒）
     * @param mileage      骑行里程（公里）
     * @param accountId    区域id
     * @return 可抵扣费用 (单位：分)
     */
    public Long getRideCardCanDeductionMoney(AdAccountFee adAccountFee, Integer ridecardType, Integer timeCount, Long money, Long rideTime, Double mileage, Integer accountId) {
        //费用减免
        if (RIDE_CARD_REDUCE.equals(ridecardType)) {
            //最大抵扣费用不超过骑行费用
            return (timeCount - money) <= 0 ? timeCount : (timeCount - money);
        }
        //时长减免
        if (RIDE_CARD_TIME.equals(ridecardType)) {
            //骑行卡时长减免=0 说明无时间限制
            if (timeCount == 0 || rideTime <= timeCount) {
                return money;
            }
            //骑行卡区分抵扣前和抵扣后
            AccountConfigExt accountConfigExt = cacheService.getAccountConfigExtByKey(accountId, AccountConfigExtConstant.ACCOUNTCONFIG_RIDEVARD);
            boolean isRideFee = false;
            //骑行卡超时才会触发
            if (accountConfigExt != null && "1".equals(accountConfigExt.getParamValue())) {
                isRideFee = true;
            }
            Double newMoney = MoneyUtil.getRide(mileage, rideTime.intValue(), adAccountFee, isRideFee);
            return (money - newMoney.longValue()) <= 0 ? money : (money - newMoney.longValue());
        }
        return 0L;
    }
}
